//mod fairings;
#[macro_use]
extern crate dotenv_codegen;

mod config1;
mod errors;
mod img_code;
mod models;
mod notes_redis_helper;
mod routes;
mod services;
mod utils;
use actix_web::{middleware::Logger, web, App, HttpServer};
use config::Environment;
use env_logger::Builder;
use errors::MyError;
use log::info;
use log::LevelFilter;
use redis_pool::RedisPool;
use routes::{gen_code, gen_code_source, init_user, login, update_user_info};
use serde::Deserialize;
use std::io::Result;
use tokio_postgres::NoTls;

fn build_redis_client(redis_addr: &str, redis_port: u16) -> Result<redis::Client> {
    let redis_url = format!("redis://{}:{}/", redis_addr, redis_port);
    println!("redis_url:{}", redis_url);
    let client = redis::Client::open(redis_url).map_err(MyError::RedisError)?;
    Ok(client)
}

#[derive(Debug, Default, Deserialize)]
pub struct AppConfig {
    pub server_addr: String,
    pub port: u16,
    pub pg: deadpool_postgres::Config,
    pub redis_addr: String,
    pub redis_port: u16,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    //env_logger::init();
    let mut builder = Builder::from_default_env();
    builder.filter_level(LevelFilter::Debug);
    builder.init();

    let config_ = config::Config::builder()
        .add_source(config::File::with_name("config.toml"))
        .add_source(Environment::with_prefix("auth2"))
        .build()
        .map_err(MyError::ConfigError)?;

    let config: AppConfig = config_.try_deserialize().map_err(MyError::ConfigError)?;
    println!("redis_addr:{}", config.redis_addr);
    println!(
        "postgres addr:{}:{}",
        config.pg.host.clone().unwrap().clone(),
        config.pg.port.unwrap()
    );

    let pool = config
        .pg
        .create_pool(None, NoTls)
        .map_err(MyError::CreatePoolError)?;
    let redis_pool = RedisPool::from(build_redis_client(&config.redis_addr, config.redis_port)?);

    println!("server addr:{}:{}", config.server_addr.clone(), config.port);
    HttpServer::new(move || {
        App::new()
            .wrap(Logger::default())
            .wrap(Logger::new("%a %{User_Agent}i"))
            .app_data(web::Data::new(pool.clone()))
            .app_data(web::Data::new(redis_pool.clone()))
            .service(init_user)
            .service(update_user_info)
            .service(login)
            .service(gen_code_source)
            .service(gen_code)
    })
    .bind((config.server_addr.clone(), config.port))?
    .run()
    .await
}
